﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.UI;
using DotNetNuke.Web.DDRMenu.DNNCommon;

namespace DotNetNuke.Web.DDRMenu.TemplateEngine
{
	public class RazorTemplateProcessor : ITemplateProcessor
	{
		private static object razor;
		private static MethodInfo getWebPage;
		private static MethodInfo execute;

		public bool LoadDefinition(TemplateDefinition baseDefinition)
		{
			var virtualPath = baseDefinition.TemplateVirtualPath;

			if (!virtualPath.EndsWith(".cshtml", StringComparison.InvariantCultureIgnoreCase) &&
				!virtualPath.EndsWith(".vbhtml", StringComparison.InvariantCultureIgnoreCase))
			{
				return false;
			}

			razor = razor ?? Activator.CreateInstance("DotNetNuke.Web.DDRMenu.NET40", "DotNetNuke.Web.DDRMenu.Razor").Unwrap();
			getWebPage = getWebPage ?? razor.GetType().GetMethod("GetWebPage");
			return (getWebPage.Invoke(razor, new object[] { virtualPath }) != null);
		}

		public void Render(object source, HtmlTextWriter htmlWriter, TemplateDefinition liveDefinition)
		{
			try
			{
				var resolver = new PathResolver(liveDefinition.Folder);
				execute = execute ?? razor.GetType().GetMethod("Execute");
				execute.Invoke(
					razor,
					new[]
					{
						liveDefinition.TemplateVirtualPath,
						htmlWriter,
						source,
						DNNContext.Current.HostControl.ClientID,
						ConvertToJson(liveDefinition.ClientOptions),
						resolver.Resolve("/", PathResolver.RelativeTo.Dnn),
						resolver.Resolve("/", PathResolver.RelativeTo.Manifest),
						resolver.Resolve("/", PathResolver.RelativeTo.Portal),
						resolver.Resolve("/", PathResolver.RelativeTo.Skin),
						liveDefinition.TemplateArguments.ToDictionary(a => a.Name, a => a.Value),
					});
			}
			catch (Exception exc)
			{
				htmlWriter.Write(exc.ToString());
			}
		}

		protected static string ConvertToJson(List<ClientOption> options)
		{
			var result = new StringBuilder();
			result.Append("{");

			if (options != null)
			{
				foreach (var option in options)
				{
					if (option is ClientNumber)
					{
						result.AppendFormat("{0}:{1},", option.Name, Utilities.ConvertToJs(Convert.ToDecimal(option.Value)));
					}
					else if (option is ClientString)
					{
						result.AppendFormat("{0}:{1},", option.Name, Utilities.ConvertToJs(option.Value));
					}
					else if (option is ClientBoolean)
					{
						result.AppendFormat(
							"{0}:{1},", option.Name, Utilities.ConvertToJs(Convert.ToBoolean(option.Value.ToLowerInvariant())));
					}
					else
					{
						result.AppendFormat("{0}:{1},", option.Name, option.Value);
					}
				}
				if (options.Count > 0)
				{
					result.Remove(result.Length - 1, 1);
				}
			}

			result.Append("}");
			return result.ToString();
		}
	}
}